package com.example.onlinemonitoring.comCenter;

import com.example.onlinemonitoring.Util.CRC16;
import com.example.onlinemonitoring.Util.CommPortManager;
import com.example.onlinemonitoring.Util.HexUtil;
import com.example.onlinemonitoring.autoRun.ComRunner;
import com.example.onlinemonitoring.model.Appdevice;
import com.example.onlinemonitoring.model.Gispdhistory;
import com.example.onlinemonitoring.model.Gispdsensor;
import com.example.onlinemonitoring.model.Scpdhistory;
import com.example.onlinemonitoring.model.Scpdsensor;
import com.example.onlinemonitoring.model.Universalhistory;
import com.example.onlinemonitoring.model.Universalsensor;
import org.springframework.context.annotation.Scope;

import com.example.onlinemonitoring.serviceImpl.GispdsensorServiceImpl;
import com.example.onlinemonitoring.serviceImpl.ScpdsensorServiceImpl;
import com.example.onlinemonitoring.serviceImpl.UniversalsensorServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.net.SocketException;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 通用设备
 * 随着外接产品越来越多，如果每个产品都新增一个com最后肯定会不堪负重和代码累赘，所以此方案旨在接入一些通用的61850、Modbus等产品，减少前后端开发时间
 */
@Service("universalCom")
@Scope("prototype")
public class UniversalCom extends CommPortManager {
    @Autowired
    private UniversalsensorServiceImpl universalserviceimpl;
    String recvmsg[] = new String[256];
    int cmdlen = 0;

    public void ClearCache() {
        for (int i = 0; i < cmdlen; i++) {
            recvmsg[i] = "";
        }
    }

    @Override
    public void receiveDatas(String str) {
        str = str.toUpperCase();
        setText(str);
        if (ad.getCommunicationmode() == 4) {
            read61850(str);
        } else {
            switch (ad.getBrand()) {
                case "大姚县":
                    DYX(str);
                    break;
                default:
                    return;
            }
        }
    }

    private void read61850(String str) {
        Universalsensor currrecord = new Universalsensor();
        currrecord.setStationid(ad.getStationid());
        currrecord.setDevicegroup(ad.getDevicegroup());
        List<Universalsensor> lastrecordlist = universalserviceimpl.getLists(currrecord);
        if (lastrecordlist.size() != 0) {
            if (lastrecordlist.get(0).getStyle61850() != null) {
                String[] style = lastrecordlist.get(0).getStyle61850().split(",");
                for (String s : style) {
                    map61850.put(s.split("\\|")[0], s.split("\\|")[1]);
                }
            }
        }
        for (Universalsensor lastrecord : lastrecordlist) {
            currrecord.setDeviceaddr(lastrecord.getDeviceaddr());
            currrecord.setPointaddr(lastrecord.getPointaddr());
            try {
                currrecord.setLastcolumn1(
                        read61850FloatValue(
                                String.format(isnull(map61850.get("Column1")), lastrecord.getDeviceaddr(),
                                        lastrecord.getPointaddr())));
                currrecord.setLastcolumn2(
                        read61850FloatValue(
                                String.format(isnull(map61850.get("Column2")), lastrecord.getDeviceaddr(),
                                        lastrecord.getPointaddr())));
                currrecord.setLastcolumn3(
                        read61850FloatValue(
                                String.format(isnull(map61850.get("Column3")), lastrecord.getDeviceaddr(),
                                        lastrecord.getPointaddr())));
                currrecord.setLastcolumn4(
                        read61850FloatValue(
                                String.format(isnull(map61850.get("Column4")), lastrecord.getDeviceaddr(),
                                        lastrecord.getPointaddr())));
                currrecord.setLastcolumn5(
                        read61850FloatValue(
                                String.format(isnull(map61850.get("Column5")), lastrecord.getDeviceaddr(),
                                        lastrecord.getPointaddr())));
                currrecord.setLastcolumn6(
                        read61850FloatValue(
                                String.format(isnull(map61850.get("Column6")), lastrecord.getDeviceaddr(),
                                        lastrecord.getPointaddr())));
            } catch (SocketException e) {
                if (Close()) {
                    universalserviceimpl.UpdateStatus(ad, 1);
                    ComRunner.netmap.remove(ad.getId());
                }
            } catch (Exception e) {
                setText("读取数据出错！" + e.toString());
            }

            int[] alarmLevel = new int[6];// 报警等级
            String alarmMessage = "";// 报警消息
            alarmLevel[0] = GetAlarmStatus(isnull(currrecord.getLastcolumn1()),
                    isnull(lastrecord.getColumn1alarmvalue()),
                    isnull(lastrecord.getColumn1alarmrelievevalue()),
                    isnull(lastrecord.getColumn1warnvalue()),
                    isnull(lastrecord.getColumn1warnrelievevalue()),
                    isnull(lastrecord.getLastalarmlevel()), true, lastrecord.getStyle().split(",")[0].split("\\|")[2],
                    lastrecord.getDevicegroup(),
                    lastrecord.getDeviceaddr(),
                    lastrecord.getPointname(), lastrecord.getPointaddr());
            alarmLevel[1] = GetAlarmStatus(isnull(currrecord.getLastcolumn2()),
                    isnull(lastrecord.getColumn2alarmvalue()),
                    isnull(lastrecord.getColumn2alarmrelievevalue()),
                    isnull(lastrecord.getColumn2warnvalue()),
                    isnull(lastrecord.getColumn2warnrelievevalue()),
                    isnull(lastrecord.getLastalarmlevel()), true, lastrecord.getStyle().split(",")[1].split("\\|")[2],
                    lastrecord.getDevicegroup(),
                    lastrecord.getDeviceaddr(),
                    lastrecord.getPointname(), lastrecord.getPointaddr());
            alarmLevel[2] = GetAlarmStatus(isnull(currrecord.getLastcolumn3()),
                    isnull(lastrecord.getColumn3alarmvalue()),
                    isnull(lastrecord.getColumn3alarmrelievevalue()),
                    isnull(lastrecord.getColumn3warnvalue()),
                    isnull(lastrecord.getColumn3warnrelievevalue()),
                    isnull(lastrecord.getLastalarmlevel()), true, lastrecord.getStyle().split(",")[2].split("\\|")[2],
                    lastrecord.getDevicegroup(),
                    lastrecord.getDeviceaddr(),
                    lastrecord.getPointname(), lastrecord.getPointaddr());
            alarmLevel[3] = GetAlarmStatus(isnull(currrecord.getLastcolumn4()),
                    isnull(lastrecord.getColumn4alarmvalue()),
                    isnull(lastrecord.getColumn4alarmrelievevalue()),
                    isnull(lastrecord.getColumn4warnvalue()),
                    isnull(lastrecord.getColumn4warnrelievevalue()),
                    isnull(lastrecord.getLastalarmlevel()), true, lastrecord.getStyle().split(",")[3].split("\\|")[2],
                    lastrecord.getDevicegroup(),
                    lastrecord.getDeviceaddr(),
                    lastrecord.getPointname(), lastrecord.getPointaddr());
            alarmLevel[4] = GetAlarmStatus(isnull(currrecord.getLastcolumn5()),
                    isnull(lastrecord.getColumn5alarmvalue()),
                    isnull(lastrecord.getColumn5alarmrelievevalue()),
                    isnull(lastrecord.getColumn5warnvalue()),
                    isnull(lastrecord.getColumn5warnrelievevalue()),
                    isnull(lastrecord.getLastalarmlevel()), true, lastrecord.getStyle().split(",")[4].split("\\|")[2],
                    lastrecord.getDevicegroup(),
                    lastrecord.getDeviceaddr(),
                    lastrecord.getPointname(), lastrecord.getPointaddr());
            alarmLevel[5] = GetAlarmStatus(isnull(currrecord.getLastcolumn6()),
                    isnull(lastrecord.getColumn6alarmvalue()),
                    isnull(lastrecord.getColumn6alarmrelievevalue()),
                    isnull(lastrecord.getColumn6warnvalue()),
                    isnull(lastrecord.getColumn6warnrelievevalue()),
                    isnull(lastrecord.getLastalarmlevel()), true, lastrecord.getStyle().split(",")[5].split("\\|")[2],
                    lastrecord.getDevicegroup(),
                    lastrecord.getDeviceaddr(),
                    lastrecord.getPointname(), lastrecord.getPointaddr());
            alarmMessage += GetAlarmMessage(alarmLevel[0], lastrecord.getStyle().split(",")[0].split("\\|")[2]);
            alarmMessage += GetAlarmMessage(alarmLevel[1], lastrecord.getStyle().split(",")[1].split("\\|")[2]);
            alarmMessage += GetAlarmMessage(alarmLevel[2], lastrecord.getStyle().split(",")[2].split("\\|")[2]);
            alarmMessage += GetAlarmMessage(alarmLevel[3], lastrecord.getStyle().split(",")[3].split("\\|")[2]);
            alarmMessage += GetAlarmMessage(alarmLevel[4], lastrecord.getStyle().split(",")[4].split("\\|")[2]);
            alarmMessage += GetAlarmMessage(alarmLevel[5], lastrecord.getStyle().split(",")[5].split("\\|")[2]);
            currrecord.setLastalarmlevel(HexUtil.MAX(alarmLevel));
            currrecord.setLastalarmmessage(alarmMessage);
            currrecord.setLastcommunicationstatus(0);
            currrecord.setLastdatatime(new Date());
            currrecord.setLasthisdatatime(addHistory(lastrecord));
            universalserviceimpl.Update(currrecord, false);
            setText("解析完成： 设备地址：" + lastrecord.getDeviceaddr() + " 监测点地址：" + lastrecord.getPointaddr());
        }
    }

    private void DYX(String str) {
        if (!str.substring(2, 4).equals("03")) {
            return;
        }
        setText("开始接收数据");
        String addrstr = str.substring(0, 2);
        Integer addrint = parsePHex4(addrstr);
        reSend[addrint] = 0;
        recvmsg[currcmd] = str.substring(6, str.length() - 4);
        boolean flag = false;
        for (int i = 0; i < cmdlen; i++) {
            if (recvmsg[i].isEmpty()) {
                flag = true;
            }
        }

        if (!flag) {
            String msg = "";
            for (int i = 0; i < cmdlen; i++) {
                msg += recvmsg[i];
            }

            Universalsensor currrecord = new Universalsensor();
            currrecord.setStationid(ad.getStationid());
            currrecord.setDevicegroup(ad.getDevicegroup());
            currrecord.setDeviceaddr(addrint);
            List<Universalsensor> list = universalserviceimpl.getLists(currrecord);
            int index = 0;
            for (Universalsensor lastrecord : list) {
                currrecord = new Universalsensor();
                currrecord.setStationid(ad.getStationid());
                currrecord.setDevicegroup(ad.getDevicegroup());
                currrecord.setDeviceaddr(addrint);
                currrecord.setPointaddr(lastrecord.getPointaddr());
                String almstr = "";
                try {
                    currrecord.setLastcolumn1(parseHex4(msg.substring(index, index + 4)) * -1f);
                    index += 4;
                    currrecord.setLastcolumn2(parseHex4(msg.substring(index, index + 4)) * -1f);
                    index += 4;
                    currrecord.setLastcolumn3((float) (parseHex4(msg.substring(index, index + 4)) * 360 / 64));
                    index += 4;
                    currrecord.setLastcolumn4(parseHex4(msg.substring(index, index + 4)) * 0.1f);
                    index += 4;
                    almstr = msg.substring(index, index + 4);
                    index += 4;
                } catch (Exception e) {
                    System.out.println(e.toString());
                }
                currrecord.setLastalarmlevel(0);
                currrecord.setLastalarmmessage("");
                String alm = "";
                if (almstr.equals("0001")) {
                    alm += "异常报警（疑似局放)";
                    currrecord.setLastalarmlevel(2);
                    currrecord.setLastalarmmessage(alm);
                }
                if (almstr.equals("0002")) {
                    alm += "持续关注";
                    currrecord.setLastalarmlevel(2);
                    currrecord.setLastalarmmessage(alm);
                }
                if (almstr.equals("0003")) {
                    alm += "重点关注";
                    currrecord.setLastalarmlevel(2);
                    currrecord.setLastalarmmessage(alm);
                }
                if (alm.length() == 0) {
                    GetNormalAlarm("局放" + lastrecord.getDeviceaddr(),lastrecord.getDevicegroup(), lastrecord.getDeviceaddr(),
                            lastrecord.getPointaddr(),
                            lastrecord.getPointname(),
                            "", false);
                    setText("无报警");
                } else {
                    GetNormalAlarm("局放" + lastrecord.getDeviceaddr(),lastrecord.getDevicegroup(), lastrecord.getDeviceaddr(),
                            lastrecord.getPointaddr(),
                            lastrecord.getPointname(),
                            alm, true);
                    setText(alm);
                }

                currrecord.setLastalarmmessage(alm);
                currrecord.setLastcommunicationstatus(0);
                currrecord.setLastdatatime(new Date());
                currrecord.setLasthisdatatime(addHistory(lastrecord));
                universalserviceimpl.Update(currrecord, false);
            }
            addrindex++;
            setText("局放16通道数据解析完毕！");
        }
    }

    private Date addHistory(Universalsensor sensor) {
        if (sensor != null) {
            if (sensor.getLasthisdatatime() == null) {
                add(sensor);
                return new Date();
            } else {
                long lasttime = 0;
                long nowtime = 0;
                try {
                    lasttime = HexUtil.todate(sensor.getLasthisdatatime()).getTime();
                    nowtime = HexUtil.todate(new Date()).getTime();
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                int timersp = 60000;
                if (sensor.getLastalarmlevel() != 0) {
                    timersp = ad.getHisalarmtimersp() * 1000;
                } else {
                    timersp = ad.getHistimersp() * 1000;
                }
                if (lasttime + timersp < nowtime) {
                    add(sensor);
                    return new Date();
                }
            }
        }
        return null;
    }

    private void add(Universalsensor sensor) {
        Universalhistory his = new Universalhistory();
        his.setStationid(sensor.getStationid());
        his.setDevicegroup(sensor.getDevicegroup());
        his.setDeviceaddr(sensor.getDeviceaddr());
        his.setPointaddr(sensor.getPointaddr());
        his.setAddrname(sensor.getAddrname());
        his.setPointname(sensor.getPointname());
        his.setDatatime(sensor.getLastdatatime());
        his.setColumn1(sensor.getLastcolumn1());
        his.setColumn2(sensor.getLastcolumn2());
        his.setColumn3(sensor.getLastcolumn3());
        his.setColumn4(sensor.getLastcolumn4());
        his.setColumn5(sensor.getLastcolumn5());
        his.setColumn6(sensor.getLastcolumn6());
        his.setColumn1alarmstatus(sensor.getLastcolumn1alarmstatus());
        his.setColumn2alarmstatus(sensor.getLastcolumn2alarmstatus());
        his.setColumn3alarmstatus(sensor.getLastcolumn3alarmstatus());
        his.setColumn4alarmstatus(sensor.getLastcolumn4alarmstatus());
        his.setColumn5alarmstatus(sensor.getLastcolumn5alarmstatus());
        his.setColumn6alarmstatus(sensor.getLastcolumn6alarmstatus());
        his.setAlarmlevel(sensor.getLastalarmlevel());
        his.setAlarmmessage(sensor.getLastalarmmessage());
        his.setMemo(sensor.getMemo());
        his.setInuse(sensor.getInuse());
        his.setStyle(sensor.getStyle());
        universalserviceimpl.Add(his);
    }

    @Async("threadPool")
    public void startSendThread(Appdevice Appdevice) throws Exception {
        String cmd[] = Appdevice.getCmd().split(",");
        cmdlen = cmd.length;
        checkType = "crc16";
        issend.put(Thread.currentThread().getId(), true);
        String cstr = "";
        while (issend.get(Thread.currentThread().getId()) != null) {
            rlock.lock();
            try {
                if (isrun) {
                    if (addrindex > Appdevice.getAddrmax() || addrindex < Appdevice.getAddrmin())
                        addrindex = Appdevice.getAddrmin();
                    currcmd = 0;
                    for (int i = 0; i < cmd.length; i++) {
                        if (currcmd == 0) {
                            ClearCache();
                        }
                        cstr = String.format(cmd[currcmd], String.format("%02X", addrindex));
                        cstr = cstr + CRC16.calcCrc16(cstr);
                        Send(cstr);
                        sendCondition.await(timeoutsp, TimeUnit.MILLISECONDS);
                        currcmd++;
                    }

                    if (reSend[addrindex] > 3) {
                        universalserviceimpl.UpdateStatus(ad, addrindex, 1);
                        reSend[addrindex] = 0;
                        addrindex++;
                    }
                    reSend[addrindex]++;
                } else if (rescode != 0) {
                    setText(resmsg[rescode]);
                }
            } catch (Exception e) {
                // TODO: handle exception
            } finally {
                rlock.unlock();
            }
        }
    }
}
